#!/usr/bin/env python
#-*- coding: utf-8 -*-

import time, sys, traceback, pickle
import gobject, gtk.gdk, gtk.glade
import graphoid, editor, simulator, drawing, config, oracle, objectlist, params, routeList

def myhook(tpe, vle, trace):
    print vle
    traceback.print_tb(trace)
    gtk.main_quit()          

class BackgroundConfig:
    def __init__(self, interface):
        gw = interface.get_widget
        self.window = gw('window2')
        self.scale = gw('hscale1')
        self.file = gw('button7')
        self.button = gw('button6')
        self.bg = None

class FileSelector:

    def get(self, message, save=False):
        if save:
            dialog = gtk.FileChooserDialog(
                message,
                None,
                gtk.FILE_CHOOSER_ACTION_SAVE,
                (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
            )
            dialog.set_do_overwrite_confirmation(True)
        else:
            dialog = gtk.FileChooserDialog(
                message,
                None,
                gtk.FILE_CHOOSER_ACTION_OPEN,
                (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
            ) 
        
        dialog.set_default_response(gtk.RESPONSE_CANCEL)
      
        resp = dialog.run()
        dialog.hide()  
        filename = None
        if resp == gtk.RESPONSE_ACCEPT:
            filename = dialog.get_filename()
        return filename

class Stats:
    
    def __init__(self, field):
        self.field = field
        self.buffer = gtk.TextBuffer()
        self.field.set_buffer(self.buffer)
        self.set()
        
    def set(self, value=None):
        if value is None:
            value = 'brak statystyk'
        self.buffer.set_text(value)
    
    def updateStats(self, stats):
        buffval = ''
        for key, val in stats.iteritems():
            buffval += key.ID + '\n'
            buffval += '\twjechało: %d \n' % val[0]
            buffval += '\twyjechało: %d \n' % val[1]
            buffval += '\tsuma czasów: %.2f \n' % val[2]
        self.set(buffval)
        
class App:

    def __init__(self):
    
        self.interface = gtk.glade.XML('ui/ui.glade')        

        gw = self.interface.get_widget

        self.window = self.interface.get_widget('window1')        
        self.canvas = self.interface.get_widget('canvas')
        
        self.b1 = gw('button1') 
        self.b2 = gw('button2')                        
        
        self.b3 = gw('button3')
        self.b4 = gw('button4')
        self.b5 = gw('button5') 
        
        self.b9 = gw('button9')        
        self.b10 = gw('button10')
        self.b11 = gw('button11')                         
        self.b12 = gw('button12') # smart mode
        
        self.b13 = gw('button13')
        self.b14 = gw('button14')
        
        self.b1.set_mode(False)
        self.b2.set_mode(False)                                          
        self.b11.set_mode(False)         
        self.b12.set_mode(False)
        
        self.b14.set_sensitive(False)
        
        self.b2.set_active(True)
        
        self.h4 = self.interface.get_widget('hbox4')
        self.h5 = self.interface.get_widget('hbox5')        
        self.h7 = self.interface.get_widget('hbox7')
        
        self.leftBox = gw('vbox2')
        
        self.tree = self.interface.get_widget('treeview1')    
        self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.tree.get_selection().connect('changed', self.handRowAct)
                    
        self.objectList = objectlist.ObjectList(self.tree)
        
        self.params = self.interface.get_widget('params')
        self.paramsTree = self.interface.get_widget('paramsTree')
        self.paramsObj = params.Params(self.paramsTree)
        
        self.bgConf = BackgroundConfig(self.interface)
        
        self.bgConf.window.connect('delete-event', self.handBGChide)
        self.bgConf.button.connect('clicked', self.handBGCshow) 
        self.bgConf.file.connect('clicked', self.handBGCfile)
        self.bgConf.scale.connect('value-changed', self.handBGCscale)
        
        self.interface.signal_autoconnect(self)

        self.width = 500 #TODO: get_allocation()
        self.height = 500

        self.gc = self.canvas.window.new_gc()
        
        self.buffer = gtk.gdk.Pixmap(self.canvas.window, self.width, self.height)

        #self.bg = gtk.gdk.pixbuf_new_from_file('./mapa.png')
        #self.bgPix = self.bg.get_pixels()
        #print self.bgPix

        self.drawing = drawing.Drawing(self.canvas)
        self.setEditor()
        
        self.hand1 = gtk.gdk.Cursor(gtk.gdk.HAND1)
        self.hand2 = gtk.gdk.Cursor(gtk.gdk.HAND2)                        
        
        self.idleID = None

        #sys.excepthook = myhook

        self.b2.activate()
        self.b12.activate()
        
        #self.editor.
        statfield = gw('textview2')
        self.stats = Stats(statfield)

        gtk.main()
    
    def setEditor(self, graph=None):
    
        if graph == None:
            graph = graphoid.graphoid()  
        self.editor = editor.Editor(graph, self.canvas, oracle.Oracle(self.window))
            
        self.editor.connect('route-created', self.objectList.addObject, 'route')
        self.editor.connect('route-deleted', self.objectList.delObject, 'route')       
        self.editor.connect('selection-changed', self.handSelectionChanged)

        self.editor.setSelection(None)
        
        self.objectList.delAll()
        for route in self.editor.graph.getRoutes():
            self.editor.emit('route-created', route) #TODO obrzydliwe?  

        self.refresh()

    def handNew(self, widget, data=None):
        self.setEditor()
            
    def handOpen(self, widget, data=None):
        fc = FileSelector()
        fname = fc.get(u'Otwórz projekt')
        if fname is not None:
            fl = open(fname)
            graph = pickle.load(fl)
            fl.close()
            
            self.setEditor(graph)
            
        
    def handSave(self, widget, data=None):
        fc = FileSelector()
        fname = fc.get('Zapisz projekt', True)
        if fname is not None:
            fl = open(fname, 'w')
            pickle.dump(self.editor.graph, fl)
            fl.close()  
        
    def handSelectionChanged(self, emitter, sel, data=None):
        """Obsługa sygnału "selection-changed" emitowanego przez edytor."""
        
        if sel.__class__ == routeList.routeList:            
            self.b14.set_sensitive(True)        
        elif sel.__class__ != graphoid.basicRoute:
            self.objectList.tree.get_selection().unselect_all()
            self.b14.set_sensitive(False)
        else:
            assert True #tutaj byc moze lepsze sprawdzenie czy zaznaczenia sie pokrywaja
            self.b14.set_sensitive(True)
        self.paramsObj.setSelection(sel)            
    
    def handRowAct(self, treeSel, data=None):
        """Obsługa sygnału "changed" selekcji listy obiektów."""
        
        #self.editor.activeRoute = None
        model, rowPaths = treeSel.get_selected_rows()
        if self.b12.get_active():
            assert model == self.objectList.routesLS
            sel = None
            if len(rowPaths) == 1:
                sel = self.objectList.routesLS[rowPaths[0]][1]
            elif len(rowPaths) > 1:
                sel = routeList.routeList(
                    [self.objectList.routesLS[path][1] for path in rowPaths]
                )
            self.editor.setSelection(sel)
        
        #self.canvas.queue_draw()        
        self.refresh()

        
    def handExpose(self, widget, data=None):
        bg = None
        if self.bgConf.bg is not None:
            bg = (self.bgConf.bg, self.bgConf.scale.get_value() / 100.0)
        self.drawing.startDrawing(bg)
        if self.b1.get_active():
            self.simulator.handSimExpose(widget, self.drawing)
            stats = self.simulator.graph.getStatistics()
            self.stats.updateStats(stats)
        elif self.b2.get_active():
            self.editor.expose(widget, self.drawing)
            cursor = None
            if self.b12.get_active():
                if self.editor.hilightEdge != None or \
                    self.editor.hilightNode != None and \
                    self.editor.selection.__class__ != graphoid.basicRoute:
                    cursor = self.hand1
            self.canvas.window.set_cursor(cursor)
        self.drawing.endDrawing()
                

    def handClick(self, widget, event): 
        if self.b2.get_active():
            if self.b12.get_active():
                self.editor.click(event) 
        self.refresh()
    

    def handRelease(self, widget, event):
        if self.b2.get_active():
            #if self.b12.get_active():
                self.editor.release(event)
        self.refresh()
    """
    def handKeyPress(self, widget, event):
        key = gtk.gdk.keyval_name(event.keyval)
        if self.b12.get_active():
            if key == 'minus' and self.editor.selection.__class__ == graphoid.basicRoute:
                self.editor.delRoute(self.editor.selection)       
            if key == 'equal':
                self.editor.addRoute()
    """

    def handMotionNotify(self, widget, event):
        #TODO czy mozliwe jest, ze event dojdzie zanim utworzony zostanie simulator/editor?
        x, y = self.widgetToWorld(event)
        if self.b1.get_active():
            self.simulator.motion(x, y)
        elif self.b2.get_active():
            self.editor.motion(x, y)
        self.refresh()
        
    def handToolClicked(self, widget, data=None):

        #self.b3.set_active(False)
        #self.b3.toggled()
        if widget == self.b1 and widget.get_active():
            self.simulator = simulator.Simulator(self.editor.graph, self.canvas)
            #self.leftBox.set_sensitive(False)
            self.h5.hide()
            self.h7.hide()
            self.h4.show()
            self.b4.set_active(True)
        elif widget == self.b2 and widget.get_active():
            #self.tree.set_sensitive(True)   
            #self.params.set_sensitive(True) 
            self.b3.set_active(True)
            #self.leftBox.set_sensitive(True)
            self.h4.hide()
            self.h5.show()
            self.h7.show()

        
        self.refresh()
    
    def handSimToolAct(self, widget, data=None):
        if not widget.get_active():
            return
        if widget == self.b3:
            if self.idleID != None: 
                if not gobject.source_remove(self.idleID):
                    assert(False)
                self.idleID = None
            self.simulator = simulator.Simulator(self.editor.graph, self.canvas)
            self.refresh()
        elif widget == self.b4:
            self.simulator.graph.start()
            if self.idleID == None:
                self.idleID = gobject.idle_add(self.refresh)
        elif widget == self.b5:
            if self.idleID != None: 
                if not gobject.source_remove(self.idleID):
                    assert(False)
                self.idleID = None        
            self.simulator.graph.pause()
    
    def handEdToolClicked(self, widget, data=None): 
               
        if widget == self.b11:
            if widget.get_active():
                #self.paramsObj.switchModel('config')                 
                self.paramsObj.setSelection(config)
                self.objectList.switchModel()              
        elif widget == self.b12:
            if widget.get_active():
                self.objectList.switchModel('route')
            else:
                self.editor.setSelection(None)
        self.canvas.queue_draw()          
    
    def handRouteAddDel(self, widget, data=None):
        if widget == self.b13:
            self.editor.addRoute()
        elif widget == self.b14:
            sel = self.editor.selection
            if sel.__class__ == graphoid.basicRoute:
                self.editor.delRoute(self.editor.selection)
            elif sel.__class__ == routeList.routeList:
                for r in sel:
                    self.editor.delRoute(r)
            else:
                assert False #zaznaczenie nie bylo obiektem klasy basicRoute ani routeList
        else:
            assert False #wywolano metode dla zlego widgetu
        
    def handDestroy(self, widget, data=None):
        gtk.main_quit()

        
    def refresh(self):
        #print time.time()
        #rect = gtk.gdk.Rectangle(0, 0, 500, 500)
        #self.canvas.window.invalidate_rect(rect, True)
        #self.canvas.window.process_updates(True)

        self.canvas.queue_draw()
        
        return True 
        
    def handBGChide(self, widget, event):
        self.bgConf.window.hide()
        return True
        
    def handBGCshow(self, widget):
        self.bgConf.window.show()    
    
    def handBGCfile(self, widget):
        fname = FileSelector().get(u'Wybierz plik tła')
        if fname is not None:
            try:
                self.bgConf.bg = gtk.gdk.pixbuf_new_from_file(fname)
                label = fname
                if len(label) > 50:
                    label = label[:25] + ' ... ' + label[-25:]
                self.bgConf.file.set_label(label)
                self.refresh()
            except:
                print u'Nie udało się otworzyć obrazka'
                self.bgConf.file.set_label(u'Wybierz plik tła...')
                self.bgConf.bg = None
                
    def handBGCscale(self, widget):
        self.refresh()
           
    
    def widgetToWorld(self, event):
        x, y = event.x, event.y
        mg = config.margin
        x = (x - mg) / (500 - 2.0 * mg)
        y = 1 - (y - mg) / (500 - 2.0 * mg)
        return x, y 
        
if __name__ == '__main__':
    app = App()

